package org.hxzon.rpggame.test;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NettyClientMain {
    private static final Logger logger = LoggerFactory.getLogger(NettyClientMain.class);
    //
    private static final String host = "localhost";
    private static final int serverPort = 8888;
    private static final int MaxFrameLength = 10240;//10k
    private static final int LengthFieldLength = 4;

    public static void main(String[] args) {
        NettyClient c = new NettyClient(host, serverPort);
        sendTestMsg("hello,世界", c);
        sendTestMsg("bye", c);
        c.close();
    }

    private static void sendTestMsg(String str, NettyClient c) {
        ByteBuf wBuf = c.newBuf();
        Util.writeCmd(wBuf, 1);
        Util.writeString(wBuf, str);
        c.sendMessage(wBuf);
    }

    public static class NettyClient {
        private EventLoopGroup workerGroup = new NioEventLoopGroup();
        private Channel channel;
        private ChannelFuture lastWriteFuture;

        public NettyClient(String host, int serverPort) {

            try {
                Bootstrap b = new Bootstrap(); // (1)
                b.group(workerGroup); // (2)
                b.channel(NioSocketChannel.class); // (3)
                b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
                b.handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(MaxFrameLength, 0, LengthFieldLength));
                        ch.pipeline().addLast(new LengthFieldPrepender(LengthFieldLength));
                        ch.pipeline().addLast(new ClientHandler());
                    }
                });

                // Start the client.
                channel = b.connect(host, serverPort).sync().channel(); // (5)

            } catch (Exception e) {
                logger.error("", e);
            } finally {

            }
        }

        public void close() {
            try {
                // Wait until all messages are flushed before closing the channel.
                if (lastWriteFuture != null) {
                    lastWriteFuture.sync();
                }
                channel.closeFuture().sync();
            } catch (Exception e) {
                logger.error("", e);
            }
            workerGroup.shutdownGracefully();
        }

        public ByteBuf newBuf() {
            return channel.alloc().buffer();
        }

        public void sendMessage(final Object msg) {
            try {
                lastWriteFuture = channel.writeAndFlush(msg);
            } catch (Exception e) {
                logger.error("", e);
            }
        }
    }

}
